package com.mango.community.service;

import com.mango.community.dao.LoginTicketMapper;
import com.mango.community.dao.UserMapper;
import com.mango.community.entity.LoginTicket;
import com.mango.community.entity.User;
import com.mango.community.util.CommunityConstant;
import com.mango.community.util.CommunityUtil;
import com.mango.community.util.MailClient;
import com.mango.community.util.RedisKeyUtil;
import org.apache.commons.lang3.StringUtils;
import org.omg.CORBA.OBJ_ADAPTER;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import javax.jws.soap.SOAPBinding;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @Author:  MangoCookieMilk
 * @Date:     2020/7/19 21:05
 */
@Service
public class UserService implements CommunityConstant {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 注入发送邮件的客户端类
     */
    @Autowired
    private MailClient mailClient;
    /**
     * 模板引擎  这是springboot 已经将thymeleaf封装成了一个对象，可以直接使用他
     */
    @Autowired
    private TemplateEngine templateEngine;
    /**
     * 注入域名
     */
    @Value("${community.path.domain}")
    private  String domain;
    /**
     * 注入项目名
     */
    @Value("${server.servlet.context-path}")
    private  String contextPath;

    /** 根据用户id查询
     * @param id
     * @return
     */
    public User findUserById(int id){
        //从缓存中获取数据
        User user = getCache(id);
        if(user == null ){
            //如果缓存中没有 初始化缓存
            user = initCache(id);
        }
        return user;
    }

    public Map<String,Object> register(User user){
        Map<String,Object> map = new HashMap<>();
        //空值判断处理
        if(user == null){
            throw new IllegalArgumentException("参数不能为空");
        }
        if(StringUtils.isBlank(user.getUserName())){
            map.put("usernameMsg","用户名不能为空");
            return map;
        }
        if(StringUtils.isBlank(user.getPassword())){
            map.put("passwordMsg","密码不能为空");
            return map;
        }
        if(StringUtils.isBlank(user.getEmail())){
            map.put("emailMsg","邮箱不能为空");
            return map;
        }
        //验证账号
        User u = userMapper.selectByName(user.getUserName());
        if (u != null){
            map.put("usernameMsg","该账号已存在！");
            return map;
        }
        //验证邮箱
        u =userMapper.selectByEmail(user.getEmail());
        if(u != null){
            map.put("emailMsg","该邮箱已经被注册！");
            return map;
        }
        //注册用户
        //生成一个随机的字符串 加盐加密
        user.setSalt(CommunityUtil.generateUUID().substring(0,5));
        //将原来的密码MD5加密+随机字符串的密码 覆盖用户传来的密码；
        user.setPassword(CommunityUtil.MD5(user.getPassword() + user.getSalt()));
        user.setType(0);
        user.setStatus(0);
        //设置随机激活码
        user.setActivationCode(CommunityUtil.generateUUID());
        //默认用户设置随机头像 %d表明这个位置是一个占位符，后面的值会替换他，值是0-1000之内的随机整数
        user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png",new Random().nextInt(1000)));
        user.setCreateTime(new Date());
        userMapper.insertUser(user);
        //激活邮件
        Context context = new Context();
        context.setVariable("email",user.getEmail());
        //设置激活邮件的访问地址并放入到 前台的html页面中
        String url = domain + contextPath + "/activation/" +user.getId() +"/"+ user.getActivationCode();
        context.setVariable("url",url);
        String content = templateEngine.process("/mail/activation",context);
        mailClient.sendMail(user.getEmail(),"激活账号",content);
        return map;
    }

    /** 激活用户的激活码
     * @param userId
     * @param code
     * @return
     */
    public int activation(int userId,String code){
        User user=userMapper.selectById(userId);
        if(user.getStatus() == 1){
            return ACTIVATION_REPEAT;
        }else if(user.getActivationCode().equals(code)){
            userMapper.updateStatus(userId,1);
            //修改了用户，需要清除缓存
            clearCache(userId);
            return ACTIVATION_SUCCESS;
        }else {
            return ACTIVATION_FAILURE;
        }
    }

    /**
     * @param username
     * @param password
     * @param expiredSeconds  前台传过来的失效时间是 秒级别的
     * @return
     * 用户登录功能的业务逻辑处理
     */
    public Map<String,Object> login(String username, String password ,int expiredSeconds){
        Map<String,Object> map = new HashMap<>();
        //空值的处理
        if(StringUtils.isBlank(username)){
            map.put("usernameMsg","账号不能为空！");
            return map;
        }
        if(StringUtils.isBlank(password)){
            map.put("passwordMsg","密码不能为空！");
            return map;
        }
        //验证账号的合法性
        User user = userMapper.selectByName(username);
        if(user == null){
            map.put("usernameMsg","该账号不存在！");
            return map;
        }
        //验证激活状态
        if(user.getStatus() == 0){
            map.put("usernameMsg","该账号未激活！");
            return map;
        }
        //验证密码
        password = CommunityUtil.MD5(password + user.getSalt());
        if(!user.getPassword().equals(password)){
            map.put("passwordMsg","密码不正确！");
            return map;
        }
        //生成登录凭证
        LoginTicket loginTicket = new LoginTicket();
        loginTicket.setUserId(user.getId());
        //使用随机字符串生成凭证
        loginTicket.setTicket(CommunityUtil.generateUUID());
        loginTicket.setStatus(0);
        //根据前台传来的失效时间设置凭证的失效时间是毫秒级别的
        loginTicket.setExpired(new Date(System.currentTimeMillis() + expiredSeconds * 1000));
        System.out.println(new Date(System.currentTimeMillis() + expiredSeconds * 1000));
        /*loginTicketMapper.insertLoginTicket(loginTicket);*/
        //获取存入redis中的ticket的key
        String redisKey = RedisKeyUtil.getTicketKey(loginTicket.getTicket());
        //存入到redis中
        redisTemplate.opsForValue().set(redisKey,loginTicket);
        map.put("ticket",loginTicket.getTicket());
        return map;
    }

    /**
     * @param ticket
     * 退出功能，将状态该为1
     */
    public void logout(String ticket){
       /* loginTicketMapper.updateStatus(ticket,1);*/
        //获取存入redis中的ticket的key
        String redisKey = RedisKeyUtil.getTicketKey(ticket);
        //从redis中取出ticket的信息
        LoginTicket loginTicket = (LoginTicket) redisTemplate.opsForValue().get(redisKey);
        //修改ticket的状态，以此来表示删除
        loginTicket.setStatus(1);
        //将修改好的信息在存入redis中
        redisTemplate.opsForValue().set(redisKey,loginTicket);
    }

    /**
     * @param ticket
     * @return
     * 通过ticket（凭证）查询出用户的id
     */
    public LoginTicket findLoginTicket(String ticket){
        /*return loginTicketMapper.selectByTicket(ticket);*/
        //获取存入redis中的ticket的key
        String redisKey = RedisKeyUtil.getTicketKey(ticket);
        //从redis中取值
        return (LoginTicket) redisTemplate.opsForValue().get(redisKey);
    }

    /** 更新用户头像
     * @param userId
     * @param headerUrl
     * @return
     */
    public int updateHeader(int userId,String headerUrl){
        int rows = userMapper.updateHeaderUrl(userId, headerUrl);
        clearCache(userId);
        return rows;
    }

    public Map<String,Object> updatePassword(int userId,String oldPassword,String newPassword){
        Map<String,Object> map = new HashMap<>();
        if(StringUtils.isBlank(oldPassword)){
            map.put("oldPasswordMsg","旧密码不能为空");
            return map;
        }
        if(StringUtils.isBlank(newPassword)){
            map.put("newPasswordMsg","新密码不能为空");
            return map;
        }
        //将用户的传来的旧密码加盐加密与数据库中的密码比较

        if(!CommunityUtil.MD5(oldPassword+userMapper.selectById(userId).getSalt()).equals(userMapper.selectById(userId).getPassword())){
            map.put("oldPasswordMsg","旧密码错误!");
            return map;
        }
        //将用户传过来的新密码跟旧密码比较
        if(CommunityUtil.MD5(newPassword + userMapper.selectById(userId).getSalt()).equals(userMapper.selectById(userId).getPassword())){
            map.put("newPasswordMsg","新密码不能与旧密码相同");
            return map;
        }
        //将密码更新
        userMapper.updatePassword(userId, CommunityUtil.MD5(newPassword + userMapper.selectById(userId).getSalt()));
        clearCache(userId);
        return map;
    }

    /** 根据用户名查询用户
     * @param userName
     * @return
     */
    public User findUserByName(String userName){
        return userMapper.selectByName(userName);
    }

    /** 从缓存中取值
     * @param userId
     * @return
     */
    private User getCache(int userId){
        //获取用户的key
        String redisKey = RedisKeyUtil.getUserKey(userId);
        return (User) redisTemplate.opsForValue().get(redisKey);
    }

    /** 在缓存中取不到值时需要从mysql数据库中取值，并且初始化redis中的数据
     * @param userId
     * @return
     */
    private User initCache(int userId){
        //从mysql中查询出数据
        User user = userMapper.selectById(userId);
        //获取用户的key
        String redisKey = RedisKeyUtil.getUserKey(userId);
        //向redis中存入数据  并且设置他的过期时间时3600 秒
        redisTemplate.opsForValue().set(redisKey,user,3600, TimeUnit.SECONDS);
        return user;
    }

    /** 数据变更时清楚缓存中的数据
     * @param userId
     */
    private void clearCache(int userId){
        //获取用户的key
        String redisKey = RedisKeyUtil.getUserKey(userId);
        //直接将redis中key删除即可
        redisTemplate.delete(redisKey);
    }
}
